import { _decorator, Component, instantiate, Node, NodePool, Prefab } from 'cc';
const { ccclass, property } = _decorator;

// 将整个系统的对象池封装整合统一获取存储使用；
// 并且结合着饿汉式单例模式的设计模式来对对象池进行优化封装；
@ccclass('NodePoolManager')
// export default和export的区别是：
// export default：每个模块只能有一个默认导出。导入时不需要花括号，可以使用任意名称
// export default：适用于导出单个主成员或模块的核心成员的情况
// export：可以导出多个成员。导入时需要使用花括号{}并且名称需要匹配，或使用as重命名
// export：适用于导出多个命名成员的情况。
export default class NodePoolManager{
    
    static _instance: NodePoolManager = new NodePoolManager();

    private _nodePoolMap: Map<string, NodePool>;

    constructor() {
        this._nodePoolMap = new Map<string, NodePool>();
    }

    static destroyInstance(){
        this._instance.clearAll();
        this._instance = null;
    }

    /**
     * @func 通过对象池从容器中获取对象池
     * @param name 对象池名字
     * @return 对象池
     */
    private getNodePoolByName(name: string): NodePool{
        // 如果不存在该名称对象池，则生成对应名字新的对象池，然后和名字放到键值对里
        if(!this._nodePoolMap.has(name)) this._nodePoolMap.set(name, new NodePool(name));
        return this._nodePoolMap.get(name);
    }

    /**
     * @func 通过对象池名字从对象池中获取节点
     * @param name 对象池名字
     * @param prefab 可选参数，对象池预制体
     * @return 对象池中的节点
     */
    public getNodeFromPool(name: string, prefab?: Prefab): Node{
        const nodePool = this.getNodePoolByName(name);
        const poolSize = nodePool.size();
        if(poolSize <= 0) nodePool.put(instantiate(prefab));
        return nodePool.get();
    }

    /**
     * @func 将节点放入对象池
     * @param name 对象池名字
     * @param node 节点
     */
    public putNodeToPool(name: string, node: Node){
        const nodePool = this.getNodePoolByName(name);
        nodePool.put(node);
        node.active = false;
        node.removeFromParent();
    }

    /**
     * @func 清空所有对象池
     */
    public clearAll(){
        // 清空所有对象池
        this._nodePoolMap.forEach((value: NodePool) => value.clear());
        // 清空对象池Map(键值对)
        this._nodePoolMap.clear();
    }
}


